import argparse, os, string, random, sys, shutil
from jinja2 import Environment, FileSystemLoader, Template
from datetime import datetime


__all__ = ['create_dirs', 'create_config', 'create_module', 'create_makefile', 'create_documentation', 'create_readmes', 'main']

def module_dir():
	"""
	Returns the directory of this module
	"""
	return os.path.dirname(os.path.realpath(__file__))
	# return sys.path[0]


def mkdirs(_dir):
	if not os.path.exists(_dir):
		os.makedirs(_dir)
		print "%s %s" % ("Created Directory:".ljust(25), _dir)
	else:
		print "%s %s" % ("Directory Exists:".ljust(25), _dir)

def create_dirs(project_args, root):
	print "%s %s (%s)" % ("Root:".ljust(25), os.path.normpath(root), os.path.abspath(root))

	project_dir = os.path.normpath(root)

	print
	mkdirs(project_dir)
	dirs = ['config', 'doc', 'doc/makefile_docs', 'doc/%s_docs'%project_args.module.lower(), 
			'examples', 'installs', 'libs', 'libs/python', 'libs/python/%s'%project_args.module.lower(),
			'src', 'src/html', 'src/html/stats', 'src/html/templates', 'src/models', 'examples/python',
			'src/parse', 'src/plots', 'src/setup', 'src/setup/tables', 'src/setup/views', 'src/stats', 'src/utilities']
	for d in dirs:
		mkdirs(project_dir+"/"+d)
	print

def create_config(project_args, root):
	project_dir = os.path.normpath(root)
	configs = module_dir()+"/configs"
	# configs = os.getcwd()+"/configs"
	print os.path.normpath(configs)

	for f in os.listdir(configs):
		if not os.path.exists(project_dir+"/config/"+f):
			with open(project_dir+"/config/"+f, 'w') as fh:
				with open(os.path.normpath(configs+"/"+f)) as fi:
					fh.write(fi.read())

			print "%s %s" % ("Created config:".ljust(25), project_dir+"/config/"+f)
		else:
			print "%s %s" % ("Config already exists:".ljust(25), project_dir+"/config/"+f)


def create_module(project_args, root):
	project_dir = os.path.normpath(root)
	templates = module_dir()+"/templates/module"
	env = Environment(loader=FileSystemLoader(os.path.normpath(templates)))

	# generates a unique key to a blowfish cipher for the new project
	cipher = ''.join(random.choice(string.ascii_lowercase + string.digits) for x in range(8))

	#template name, output name
	modules  = [('module.py', '__init__.py'),
				('exceptions.py', 'exceptions.py'),
				('html.py', 'html.py'),
				('shell.py', 'shell.py'),
				('blowfish.py', 'blowfish.py'),
				('utilities.py', 'utilities.py'),
				('validations.py', 'validations.py'),
				('crypto.py', 'crypto.py')]

	mkdirs(project_dir+"/libs/python/%s" % project_args.module)

	for template, new in modules:

		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, cipher=cipher)

		if not os.path.exists(project_dir+"/libs/python/%s/%s" % (project_args.module, new)):
			with open(project_dir+"/libs/python/%s/%s" % (project_args.module, new), 'w') as m:
				print "Creating %s" % new
				m.write(output)
		else:
			print "Skipping %s" % new

def create_makefile(project_args, root):
	project_dir = os.path.normpath(root)
	templates = module_dir()+"/templates"
	env = Environment(loader=FileSystemLoader(os.path.normpath(templates)))

	#template name, output name
	modules  = [('makefile.py', 'Makefile.py')]

	for template, new in modules:

		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name)

		if not os.path.exists(project_dir+"/%s" % new):
			with open(project_dir+"/%s" % new, 'w') as m:
				print "Creating %s" % new
				m.write(output)
		else:
			print "Skipping %s" % new


def create_documentation(project_args, doc_root, templates):
	
	mkdirs(os.path.normpath(doc_root+"/build"))
	mkdirs(os.path.normpath(doc_root+"/source"))
	mkdirs(os.path.normpath(doc_root+"/source/_static"))
	mkdirs(os.path.normpath(doc_root+"/source/_templates"))
	
	project_dir = os.path.normpath(project_args.dir+"/"+project_args.project_name)
	env = Environment(loader=FileSystemLoader(os.path.normpath(module_dir()+"/templates/doc")))

	# adding makefiles for sphinx
	templates.extend([('sphinx_Makefile','Makefile'), ('sphinx_make.bat.txt','make.bat')])

	# create all documentation templates
	for template, new in templates:
		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, year=datetime.now().year, len=len)

		if not os.path.exists(doc_root+"/%s" % (new)):
			with open(doc_root+"/%s" % (new), 'w') as m:
				print "Creating %s" % new
				m.write(output)
		else:
			print "Skipping %s" % new


def create_readmes(project_args):
	project_dir = os.path.normpath(project_args.dir+"/"+project_args.project_name)
	readme_dir = os.path.normpath(module_dir()+"/templates/readmes")

	readmes =  [('html.txt', '/src/html'),
				('models.txt', '/src/models'),
				('parse.txt', '/src/parse'),
				('plots.txt', '/src/plots'), 
				('setup.txt', '/src/setup'), 
				('stats.txt', '/src/stats'), 
				('utilities.txt', '/src/utilities'),
				('installs.txt', '/installs')]

	for readme, dst in readmes:
		if not os.path.exists("%s/%s/README.txt" % (project_dir, dst)):
			with open("%s/%s/README.txt" % (project_dir, dst), 'w') as o:
				with open(os.path.normpath("%s/%s"% (readme_dir, readme))) as i:
					print "Creating %s" % os.path.normpath("%s/%s"% (readme_dir, readme))
					o.write(i.read())
		else:
			print "Skipping %s" % os.path.normpath("%s/%s"% (readme_dir, readme))

def create_setup(project_args):
	project_dir = os.path.normpath(project_args.dir+"/"+project_args.project_name)
	setup_dir = os.path.normpath(module_dir()+"/templates/src/setup")
	env = Environment(loader=FileSystemLoader(os.path.normpath(module_dir()+"/templates/src/setup")))

	setups = [('create_databases.sql', '/src/setup'),
						('setup_db.py', '/src/setup'),
						('setup_config_db.py', '/src/setup'),
						('setup_db_users.py', '/src/setup'),
						('create_tables.sql', '/src/setup/tables'),
						('create_views.sql', '/src/setup/views')]

	# create all documentation templates
	for template, new in setups:
		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, year=datetime.now().year, len=len)
		
		if not os.path.exists(project_dir+"/%s/%s" % (new, template)):
			with open(project_dir+"/%s/%s" % (new, template), 'w') as m:
				print "Creating %s" % (new+"/"+template)
				m.write(output)
		else:
			print "Skipping %s" % (new+"/"+template)

def create_utilities(project_args):
	project_dir = os.path.normpath(project_args.dir+"/"+project_args.project_name)
	setup_dir = os.path.normpath(module_dir()+"/templates/src/utilities")
	env = Environment(loader=FileSystemLoader(os.path.normpath(module_dir()+"/templates/src/utilities")))

	setups = [('change_analysis_event.py', '/src/utilities'),
						('change_host.py', '/src/utilities'),
						('generate_blowfish.py', '/src/utilities'),
						('current_configuration.py', '/src/utilities')]

	# create all documentation templates
	for template, new in setups:
		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, year=datetime.now().year, len=len)
		
		if not os.path.exists(project_dir+"/%s/%s" % (new, template)):
			with open(project_dir+"/%s/%s" % (new, template), 'w') as m:
				print "Creating %s" % (new+"/"+template)
				m.write(output)
		else:
			print "Skipping %s" % (new+"/"+template)

def create_html(project_args):
	project_dir = os.path.normpath(project_args.dir+"/"+project_args.project_name)
	html_dir = os.path.normpath(module_dir()+"/templates/src/html")
	
	def _ignore(path, names):
		return []
	
	if not os.path.exists(project_dir+"/src/html/base_init"):
		shutil.copytree(module_dir()+'/templates/src/html/base_init/', project_dir+"/src/html/base_init")
	
	# if not os.path.exists(project_dir+"/src/html/templates"):
		# shutil.copytree(module_dir()+'/templates/src/html/templates/', project_dir+"/src/html/templates")

	env = Environment(loader=FileSystemLoader(os.path.normpath(module_dir()+"/templates/src/html")))

	htmls = [('setup.py', '/src/html'),
						('index.py', '/src/html'),
						('build.py', '/src/html')]

	# create all documentation templates
	for template, new in htmls:
		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, year=datetime.now().year, len=len)
		
		if not os.path.exists(project_dir+"/%s/%s" % (new, template)):
			with open(project_dir+"/%s/%s" % (new, template), 'w') as m:
				print "Creating %s" % (new+"/"+template)
				m.write(output)
		else:
			print "Skipping %s" % (new+"/"+template)

	htmls = [
						('templates/seealso.html', '/src/html/'),
						('templates/link.html', '/src/html/'),
						('templates/table.html', '/src/html/'),
						('templates/highlight.html', '/src/html/')]

	# create all documentation templates
	for template, new in htmls:
		# module = env.get_template(template)
		# output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name, year=datetime.now().year, len=len)
		
		if not os.path.exists(project_dir+"/%s/%s" % (new, template)):
			with open(project_dir+"/%s/%s" % (new, template), 'w') as m:
				with open(module_dir()+"/templates/src/html/%s" % template) as fi:
					print "Creating %s" % (new+""+template)
					m.write(fi.read())
		else:
			print "Skipping %s" % (new+""+template)

def create_models(project_args, root):
	project_dir = os.path.normpath(root)
	templates = module_dir()+"/templates/src/models"
	env = Environment(loader=FileSystemLoader(os.path.normpath(templates)))

	#template name, output name
	modules  = [('config_model.py', 'config_model.py')]

	for template, new in modules:

		module = env.get_template(template)
		output = module.render(module=project_args.module, authors=project_args.authors, project_name=project_args.project_name)

		if not os.path.exists(project_dir+"/src/models/%s" % new):
			with open(project_dir+"/src/models/%s" % new, 'w') as m:
				print "Creating %s" % new
				m.write(output)
		else:
			print "Skipping %s" % new

def main(args):

	summary = []
	summary.append("%s %s" % ("Project Name:".ljust(15), args.project_name))
	summary.append("%s %s" % ("Module:".ljust(15), args.module))
	summary.append("%s %s" % ("Authors:".ljust(15), args.authors))
	summary.append("%s %s" % ("Root Dir:".ljust(15), args.dir))

	print "\n"+"-"*max([len(s) for s in summary])
	print '\n'.join(summary)
	print "-"*max([len(s) for s in summary])

	print "\nCreating Directories:"
	create_dirs(args, args.dir+"/"+args.project_name)

	print "\nCreating Config Files:"
	create_config(args, args.dir+"/"+args.project_name)

	print "\nCreating '%s' module:" % args.module
	create_module(args, args.dir+"/"+args.project_name)

	# print "\nCreating Makefile:"
	create_makefile(args, args.dir+"/"+args.project_name)

	#template name, output name
	templates  = [('conf.py', '/source/conf.py'),
				('makefile_index.rst', '/source/index.rst'), 
				('makefile.rst', '/source/makefile.rst')]

	# create makefile docs
	create_documentation(args, '%s/%s/doc/makefile_docs' % (args.dir, args.project_name), templates)

	#template name, output name
	templates  = [('conf.py', '/source/conf.py'),
				('module_index.rst', '/source/index.rst'), 
				('module.rst', '/source/%s.rst' % args.module.lower())]

	# create module docs
	create_documentation(args, '%s/%s/doc/%s_docs' % (args.dir, args.project_name, args.module.lower()), templates)

	# create readmes
	create_readmes(args)

	# create setups
	create_setup(args)

	# create utilities scripts
	create_utilities(args)

	# create html scripts
	create_html(args)

	# create default models
	create_models(args, args.dir+"/"+args.project_name)


if __name__ == '__main__':

	desc = "This script produces the directory structure of a new Spyrim analysis project. "
	parser = argparse.ArgumentParser(description=desc)

	parser.add_argument('-p', '--project_name', required=True, dest='project_name', help='Name of the new Spyrim project. (Required)')
	parser.add_argument('-m', '--module_name', required=True, dest='module', help='Name of the Python module to be created. (Required)')
	parser.add_argument('-a', '--authors', required=True, dest='authors', help='Stores the author(s) name. (Required)')
	parser.add_argument('-d', '--dir', required=True, dest='dir', help='Directory of the new Spyrim project to be created. (Required)')
	# parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='Prints more information')

	# args = parser.parse_args()
	args = parser.parse_args(['-p','PyPI Analysis','-m','PyPIAnalysis','-a','Max Franks','-d','../spyrim_test2'])
	# args = parser.parse_args(['-h'])

	# for m in os.listdir(os.path.abspath(module_dir())):
		# if str(m) == "__init__.py":
			
			#import module as Python module
			# module = __import__(m.split(".")[0])
			# print os.path.dirname(module.__file__)
	
	main(args)


